using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

using Deepcode.Flux.Core.Services.XML;
using Deepcode.Flux.Core.Systems.Workflow;
using Deepcode.Flux.Core.Systems.Workflow.Info;
using Deepcode.Flux.Core.Systems.Workflow.Bases;
using Deepcode.Flux.Core.Systems.Workflow.Attribs;
using Deepcode.Flux.Core.Systems.Workflow.Enums;
using Deepcode.Flux.Core.Systems.Security;
using Deepcode.Flux.Core.Systems.Audit.Quick;
using Deepcode.Flux.Core.Services.Assistant;

namespace Deepcode.Flux.Core.Systems.Workflow.BaseHandlers
{
	public class FluxBaseHandler : BaseHandler
	{
		#region Operator / Group Queries
		/// <summary>
		/// Returns the various operators within the Flux.NET Roles based security system
		/// </summary>
		/// <returns></returns>
		public override WorkflowTaskableOperators GetTaskableOperators()
		{
			WorkflowTaskableOperators ops = new WorkflowTaskableOperators();
			AdministrationUsers users = new AdministrationUsers();
			foreach( AdministrationUser user in users.GetAllUsers())
			{
				WorkflowTaskableOperator op = new WorkflowTaskableOperator();
				op.OperatorID = user.PK_ID;
				op.OperatorName = user.RealName;
				op.Email = user.EMailAddress;
				ops.Add(op);
			}
			return ops;
		}
		/// <summary>
		/// Returns the various user groups from within Flux.NET Roles based security
		/// </summary>
		/// <returns></returns>
		public override WorkflowTaskableGroups GetTaskableGroups()
		{
			WorkflowTaskableGroups grps = new WorkflowTaskableGroups();
			AdministrationGroups groups = new AdministrationGroups();

			foreach (AdministrationGroup g in groups.GetAllGroups())
			{
				WorkflowTaskableGroup grp = new WorkflowTaskableGroup();
				grp.GroupID = g.PK_ID;
				grp.GroupName = g.GroupName;
				grps.Add(grp);
			}

			return grps;
		}
		/// <summary>
		/// Returns information about one operator from within the Flux.NET Roles based security system
		/// </summary>
		/// <param name="OperatorID"></param>
		/// <returns></returns>
		public override WorkflowTaskableOperator GetTaskableOperator(int OperatorID)
		{
			AdministrationUsers users = new AdministrationUsers();
			AdministrationUser u = users.GetUserByID( OperatorID );
			if( u == null ) return null;

			WorkflowTaskableOperator wto = new WorkflowTaskableOperator();
			wto.OperatorID = u.PK_ID;
			wto.OperatorName = u.RealName;
			wto.Email = u.EMailAddress;
			return wto;
		}
		/// <summary>
		/// Returns information about one group from within the Flux.NET Roles based security system
		/// </summary>
		/// <param name="GroupID"></param>
		/// <returns></returns>
		public override WorkflowTaskableGroup GetTaskableGroup(int GroupID)
		{
			AdministrationGroups groups = new AdministrationGroups();
			AdministrationGroup g = groups.GetGroupByID( GroupID );
			if( g == null ) return null;
			
			WorkflowTaskableGroup wtg = new WorkflowTaskableGroup();
			wtg.GroupID = g.PK_ID;
			wtg.GroupName = g.GroupName;
			return wtg;
		}
		/// <summary>
		/// Returns all operators within a particular group
		/// </summary>
		/// <param name="GroupID"></param>
		/// <returns></returns>
		public override WorkflowTaskableOperators GetTaskableOperatorsForGroup(int GroupID)
		{
			WorkflowTaskableOperators ops = new WorkflowTaskableOperators();
			AdministrationUsers users = new AdministrationUsers();
			foreach (AdministrationUser user in users.GetAllUsersInGroup(GroupID))
			{
				WorkflowTaskableOperator op = new WorkflowTaskableOperator();
				op.OperatorID = user.PK_ID;
				op.OperatorName = user.RealName;
				op.Email = user.EMailAddress;
				ops.Add(op);
			}
			return ops;
		}
		#endregion
		#region Send an email action
		/// <summary>
		/// Implements a simple send email system
		/// that allows the subject, to address, and body text
		/// to be specified.
		/// </summary>
		[WorkflowMethod("Send an Email", "Deepcode.Flux.Core.Systems.Workflow.BaseHandlers.SendAnEmailConfig,Deepcode.Flux.Core")]
		public void SendAnEmail(WorkflowEngine Engine, int ProcessID, int DataID, string DataName, string propertyBag)
		{
			// Load the property bag
			PropertyBag pb = new PropertyBag(propertyBag);

			// Load standard items through workflow dictionary
			string SubjectLine = Engine.ProcessDictionaryField( pb.Get("Subject", ""), DataID);
			string BodyText = Engine.ProcessDictionaryField( pb.Get("Body", ""), DataID);

			// Process emails
			string ToEmail = Engine.ProcessDictionaryField(
				GetEmailsForBag( pb, Engine, ProcessID, DataID, DataName ), 
				DataID);

			if (ToEmail == "") return;
			string [] EMs = ToEmail.Split(';');
			foreach (string EM in EMs)
			{
				if( EM == "" ) continue;
				try
				{
					// Setup the email
					Deepcode.Flux.Core.Services.MailHandlers.StandardMailMessage m = new Deepcode.Flux.Core.Services.MailHandlers.StandardMailMessage();
					m.From = Deepcode.Flux.Core.Services.Configuration.FluxConfig.SystemEmail;
					m.To = EM;
					m.Subject = SubjectLine;
					m.BodyIsHtml = false;
					m.Body = BodyText;
					m.Send();
				}
				catch (Exception e)
				{
					QuickAudit.RaiseError(
						new AuditUser(),
						"Workflow",
						"SendAnEmail",
						"SendAnEmail workflow action failed. DataName=({0}), Reason for fail: {1}",
						DataName, e.Message);
				}
			}
		}
		#endregion
		#region Utilities
		/// <summary>
		/// Get the de-duped email addresses from 
		/// the various fields in the property bag.
		/// </summary>
		/// <param name="pb"></param>
		/// <param name="Engine"></param>
		/// <param name="DataID"></param>
		/// <returns></returns>
		protected string GetEmailsForBag(PropertyBag pb, WorkflowEngine Engine, int ProcessID, int DataID, string DataName)
		{
			// Prepare vars
			List<string> DestinationEmails = new List<string>();

			// Add in direct email addresses
			string[] directem = ListUtil.GetCSVStrings(pb.Get("ToEmails", ""));
			foreach (string dem in directem)
				if( dem != "" )
					DestinationEmails.Add(dem);

			// Get the operators specified directly
			int[] emops = ListUtil.GetCSVInts(pb.Get("ToOperators", ""));
			foreach (int emo in emops)
			{
				WorkflowTaskableOperator op = this.GetTaskableOperator( emo );
				if( op != null )
					if( op.Email != "" ) 
						DestinationEmails.Add( op.Email );
			}

			// Get the groups specified directly
			int[] emgroups = ListUtil.GetCSVInts(pb.Get("ToGroups", ""));
			foreach (int emg in emgroups)
			{
				WorkflowTaskableOperators ops = this.GetTaskableOperatorsForGroup( emg );
				foreach (WorkflowTaskableOperator op in ops)
					if( op.Email != "" )
						DestinationEmails.Add( op.Email );
			}

			string[] emmethods = ListUtil.GetCSVStrings( pb.Get("ToMethods", "") );
			foreach (string emm in emmethods)
			{
				int [] GroupIDs = Engine.InvokeUserMethod( UserCallbackType.REQUEST_GROUPS, emm, ProcessID, DataID, DataName );
				int [] UserIDs = Engine.InvokeUserMethod( UserCallbackType.REQUEST_USERS, emm, ProcessID, DataID, DataName );
				if( (GroupIDs != null) && (GroupIDs.Length>0) )
				{
					foreach (int GID in GroupIDs)
					{
						WorkflowTaskableOperators ops = this.GetTaskableOperatorsForGroup(GID);
						foreach (WorkflowTaskableOperator op in ops)
							if (op.Email != "")
								DestinationEmails.Add(op.Email);
					}
				}
				if( (UserIDs != null ) && (UserIDs.Length>0) )
				{
					foreach (int UID in UserIDs)
					{
						WorkflowTaskableOperator op = this.GetTaskableOperator( UID );
						if( op != null )
							if( op.Email != "" )
								DestinationEmails.Add( op.Email );
					}
				}
			}

			ArrayList deduped = ListUtil.DeDupeList( DestinationEmails.ToArray() );
			string result = "";
			foreach (string r in deduped )
			{
				if( result != "" ) result += ";";
				result += r;
			}
			return result;
		}
		#endregion
	}
}
